// This File is part of the "nyaqt" Project
// 
// Copyright  2009 sometmes@gmail.com
// All rights reserved
// 
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.



using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using ICSharpCode.TextEditor.Document;
using System.IO;
using System.Text.RegularExpressions;
using System.Collections.Specialized;
using nyaqt.Plugins;

namespace nyaqt
{
    public partial class EditingTabController : UserControl
    {
        private const string _defaultsql = @"";
        private string fileName;
        int lastUndoItemCount;
        ConnectionInfo _connection = new EmptyConnectionInfo();
        TabTitleStyleEnum tabTitleStyle = TabTitleStyleEnum.FileName | TabTitleStyleEnum.Server | TabTitleStyleEnum.Database;
        StatementExecutionController _execController = new StatementExecutionController();

        public delegate void StatusChangeDelegate(int rowcount,bool loading);
        public event StatusChangeDelegate StatusChange;

        EnabledState _enabledState = new EnabledState();
        public TimeSpan ExecDuration
        {
            get
            {
                return _execController.ExecDuration;
            }
        }

        Dictionary<string, ContextMenuStrip> _tabMenus;
        public Dictionary<string, ContextMenuStrip> TabMenus
        {
            get { return _tabMenus; }
            set { _tabMenus = value; }
        }

        public EditingTabController()
        {
            InitializeComponent();

            splitContainer1.Dock = DockStyle.Fill;
            resultsTabControl.Dock = DockStyle.Fill;

            queryTextEditor.Dock = DockStyle.Fill;


            string appPath = System.IO.Path.GetDirectoryName(Application.ExecutablePath);
            HighlightingManager.Manager.AddSyntaxModeFileProvider(new FileSyntaxModeProvider(appPath));

            queryTextEditor.Document.HighlightingStrategy = HighlightingStrategyFactory.CreateHighlightingStrategy("GENERICSQL");
            queryTextEditor.ShowEOLMarkers = false;
            queryTextEditor.Document.DocumentChanged += new DocumentEventHandler(Document_DocumentChanged);
            queryTextEditor.Document.UndoStack.ActionUndone += new EventHandler(UndoStack_Action);
            queryTextEditor.Document.UndoStack.ActionRedone += new EventHandler(UndoStack_Action);
            queryTextEditor.ActiveTextAreaControl.TextArea.KeyPress += new KeyPressEventHandler(TextArea_KeyPress);
            queryTextEditor.ActiveTextAreaControl.TextArea.KeyDown += new KeyEventHandler(TextArea_KeyDown);
            

            resultsTabControl.TabPages.Clear();
            _execController = new StatementExecutionController();
            _execController.ExecuteAsyncMessage += new StatementExecutionController.ExecuteAsyncMessageDelegate(_execController_ExecuteAsyncMessage);
            _execController.ExecuteAsyncNewResult += new StatementExecutionController.ExecuteAsyncNewResultDelegate(_execController_ExecuteAsyncNewResult);
            _execController.Start += new StatementExecutionController.StartDelegate(_execController_Start);
            _execController.End += new StatementExecutionController.EndDelegate(_execController_End);
            _execController.ExecuteAsyncRowFetchComplete += new StatementExecutionController.ExecuteAsyncRowFetchCompleteDelegate(_execController_ExecuteAsyncRowFetchComplete);

            queryTextEditor.Text = _defaultsql;
//            for (int i = 0; i < 400; i++)
//                queryTextEditor.Text += @"xxxxxxxxxxxxxxxxxxxxxxxxxxx
////";
            //            queryTextEditor.Text = @"
//declare @id varchar(100)
//set @id = '23'
//-- #endregion declare
//
//print 'first'
//print @id
//go
//print 'second'
//print @id
//go
//select top 10 * from cliente
//--select * from AdventureWorks.Person.AddressType
//--select * from AdventureWorks.Production.WorkOrder
//";

            CreateGridTab();
            //CreateTextTab();
        }

        public delegate FindOptions UpdateFindTextDelegate(string textToFind);
        public event UpdateFindTextDelegate UpdateFindText;

        void SelectCurrentWord()
        {
            ICSharpCode.TextEditor.TextAreaControl textArea = queryTextEditor.ActiveTextAreaControl;
            if (textArea.SelectionManager.HasSomethingSelected) return;
            ICSharpCode.TextEditor.Document.IDocument doc = queryTextEditor.Document;
            int current = textArea.Caret.Offset;

            int start = TextUtilities.FindPrevWordStart(doc, current);
            int end = TextUtilities.FindWordEnd(doc, current);

            textArea.SelectionManager.SetSelection(textArea.Document.OffsetToPosition(start), textArea.Document.OffsetToPosition(end));
        }

        void TextArea_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Control && e.KeyCode == Keys.F3)
            {
                ICSharpCode.TextEditor.TextAreaControl textArea = queryTextEditor.ActiveTextAreaControl;
                SelectCurrentWord();
                FindOptions options = UpdateFindText(textArea.SelectionManager.SelectedText);
                if (e.Shift)
                    FindPrevious(textArea.SelectionManager.SelectedText, options);
                else
                    FindNext(textArea.SelectionManager.SelectedText, options);
            }
        }

        void TextArea_KeyPress(object sender, KeyPressEventArgs e)
        {
            
        }

        public EnabledState EnabledState
        {
            get { return _enabledState; }
        }

        internal StatementExecutionController ExecController
        {
            get { return _execController; }
        }


        [Flags]
        public enum TabTitleStyleEnum
        {
            FileName = 1,
            FilePath = 2,
            Server = 4,
            Database = 8,
            DbUser = 16
        }

        public void UpdateTabTitle(bool force)
        {
            string tabtitle= "";
            if (this.fileName != null && (this.tabTitleStyle & TabTitleStyleEnum.FilePath) == TabTitleStyleEnum.FilePath)
                tabtitle += Path.GetDirectoryName(this.fileName);
            if (this.fileName != null && (this.tabTitleStyle & TabTitleStyleEnum.FileName) == TabTitleStyleEnum.FileName)
                tabtitle += (tabtitle == "" ? "" : "\\") + Path.GetFileName(this.fileName);
            if (this._connection.Current != null && (this.tabTitleStyle & TabTitleStyleEnum.Server) == TabTitleStyleEnum.Server)
                tabtitle += (tabtitle == "" ? "" : ":") + _connection.ConnectionProperties.Server;
            if (this._connection.Current != null && (this.tabTitleStyle & TabTitleStyleEnum.Database) == TabTitleStyleEnum.Database)
                tabtitle += (tabtitle == "" ? "" : ":") + _connection.ConnectionProperties.Database;
            if (this._connection.Current != null && (this.tabTitleStyle & TabTitleStyleEnum.DbUser) == TabTitleStyleEnum.DbUser)
                tabtitle += (tabtitle == "" ? "" : ":") + _connection.ConnectionProperties.UserName;
            if (tabtitle != "")
            {
                if (force || queryTabPage.Text == "" || !_userSelectedTabTitle)
                    queryTabPage.Text = tabtitle;
            }
            if (this.fileName != null)
                queryTabPage.ToolTipText = this.fileName;
            else
                queryTabPage.ToolTipText = "";
        }

        bool _userSelectedTabTitle = false;

        public bool UserSelectedTabTitle
        {
            get { return _userSelectedTabTitle; }
            set { _userSelectedTabTitle = value; }
        }


        public TabTitleStyleEnum TabTitleStyle
        {
            get { return tabTitleStyle; }
            set { tabTitleStyle = value; }
        }

        public ConnectionInfo ConnectionInfo
        {
            get { return _connection; }
            set
            {
                _connection = value;
                if (_testCommand != null && value.Current != null)
                    _testCommand.Command.Connection = value.Current;
            }
        }

        public string FileName
        {
            get { return fileName; }
            set { fileName = value; }
        }

        public string Statement
        {
            get 
            {
                string sel = "";
                sel = queryTextEditor.ActiveTextAreaControl.SelectionManager.SelectedText;
                if (string.IsNullOrEmpty(sel))
                    sel = queryTextEditor.Text;
                return sel;
            }

            set
            {
                queryTextEditor.Text = value;
            }
        }

        public Point Selection
        {
            get
            {
                Point ret = new Point();
                if (queryTextEditor.ActiveTextAreaControl.SelectionManager.HasSomethingSelected)
                {
                    ISelection sel = queryTextEditor.ActiveTextAreaControl.SelectionManager.SelectionCollection[0];
                    ret.X = sel.Offset;
                    ret.Y = sel.EndOffset - 1; // bug in ICSharp.TextEditor �?
                }
                else
                {
                    ret.X = 0;
                    ret.Y = queryTextEditor.ActiveTextAreaControl.Document.TextLength - 1;
                }
                return ret;
            }
        }

        public string Script
        {
            get
            {
                return queryTextEditor.Text;
            }

            set
            {
                queryTextEditor.Text = value;
            }
        }

        nyaqt.Plugins.TestCommand _testCommand;

        public nyaqt.Plugins.TestCommand TestCommand
        {
            get { return _testCommand; }
            set { _testCommand = value; }
        }

        void _execController_Start()
        {
            resultsTabControl.TabPages.Clear();
            _textTab = null;
            _loadingDataTable = null;
            _loadingResultTab = null;
            _resultsCount = -1;
        }

        void _execController_End()
        {
            timerRowCount.Enabled = false;
        }

        void UndoStack_Action(object sender, EventArgs e)
        {
            if (this.lastUndoItemCount == queryTextEditor.Document.UndoStack.UndoItemCount)
                RemoveChangedMark();
        }

        private void RemoveChangedMark()
        {
            string text = this.queryTabPage.Text;
            if (text.EndsWith("*"))
                this.queryTabPage.Text = text.Remove(text.Length - 1);
        }

        void Document_DocumentChanged(object sender, DocumentEventArgs e)
        {
            string text = this.queryTabPage.Text;
            if (!text.EndsWith("*"))
                this.queryTabPage.Text = text + "*";
        }

        public TabPage Tab
        {
            get { return queryTabPage; }
        }

        public bool Save()
        {
            if (fileName == null)
                fileName = UserQuerySave();
            if (fileName == null)
                return false;
            queryTextEditor.SaveFile(this.fileName);
            this.lastUndoItemCount = queryTextEditor.Document.UndoStack.UndoItemCount;

            RemoveChangedMark();

            return true;
        }

        private string UserQuerySave()
        {
            if (DialogResult.OK == saveFileDialog1.ShowDialog())
                return saveFileDialog1.FileName;
            else
                return null;
        }

        private DialogResult UserQueryClose()
        {
            return MessageBox.Show("\"" + this.queryTabPage.Text + "\"" + " " + SR.QuerySaveNow, SR.TitleQuerySaveNow, MessageBoxButtons.YesNoCancel);
        }

        public void Close()
        {
            if (queryTextEditor.Document.UndoStack.UndoItemCount != this.lastUndoItemCount)
            {
                DialogResult res = UserQueryClose();
                if (res == DialogResult.Yes)
                {
                    if (false == Save())
                        return;
                }
                else if (res == DialogResult.Cancel)
                {
                    return;
                }
            }
            TabControl tabCtrl = this.queryTabPage.Parent as TabControl;
            tabCtrl.TabPages.Remove(this.queryTabPage);
        }

        public bool IsEmpty
        {
            get
            {
                return queryTextEditor.Document.TextLength == 0;
            }
        }

        public void Reload()
        {
            if (_testCommand != null)
            {
                string simul = _connection.ConnectionProperties.SimulateParamsUse(_testCommand.Parameters);
                string lineComment = ConnectionInfo.ConnectionProperties.LineCommentString;
                queryTextEditor.Text = TextUtils.InsertBeforeEndDeclareRegion(simul, _testCommand.Command.CommandText, lineComment); ;
            }
            else if (!string.IsNullOrEmpty(this.FileName))
            {
                queryTextEditor.LoadFile(this.fileName);
                this.lastUndoItemCount = queryTextEditor.Document.UndoStack.UndoItemCount;
                RemoveChangedMark();
            }
        }

        private void UserControl1_Load(object sender, EventArgs e)
        {
        }

        public void SwitchPane()
        {
            if (queryTextEditor.ActiveTextAreaControl.TextArea.Focused == true)
            {
                TabPage gridTab = resultsTabControl.SelectedTab;
                if (gridTab == null) return;
                TabControl tc = gridTab.Controls[0] as TabControl;
                TabPage page = tc.SelectedTab;
                if (page == null) return;
                Control grid = page.Controls[0];
                grid.Focus();
            }
            else
            {
                queryTextEditor.Focus();
            }
        }

        private void resultsTabControl_DoubleClick(object sender, EventArgs e)
        {
            object o = queryTextEditor.Document.UndoStack.UndoItemCount;
        }

        int _resultsCount = -1;
        TabPage CreateGridTab()
        {
            TabPage page = new TabPage("Resultset " + (_resultsCount + 1));
            TabControl dataAndSchema = new TabControl();
            dataAndSchema.Left = -2;
            dataAndSchema.Top = 0;
            dataAndSchema.Width = page.Width - (dataAndSchema.Left * 2);
            dataAndSchema.Height = page.Height - dataAndSchema.Left;
            dataAndSchema.Anchor = AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top | AnchorStyles.Bottom;

            TabPage data = new TabPage("Data");
            data.Name = "dataTabPage";
            PagedGridView grid = new PagedGridView();
            grid.DoubleClick += new EventHandler(grid_DoubleClick);
            grid.DisableConstraints += new PagedGridView.DisableConstraintsDelegate(grid_DisableConstraints);
            grid.Dock = DockStyle.Fill;
            grid.RowContextMenuStripNeeded += new DataGridViewRowContextMenuStripNeededEventHandler(grid_RowContextMenuStripNeeded);
            grid.CellContextMenuStripNeeded += new DataGridViewCellContextMenuStripNeededEventHandler(grid_CellContextMenuStripNeeded);
            grid.ColumnHeaderMouseClick += new DataGridViewCellMouseEventHandler(grid_ColumnHeaderMouseClick);
            grid.ColumnHeaderMouseDoubleClick += new DataGridViewCellMouseEventHandler(grid_ColumnHeaderMouseDoubleClick);
            grid.RowHeaderMouseClick += new DataGridViewCellMouseEventHandler(grid_RowHeaderMouseClick);
            grid.RowHeaderMouseDoubleClick += new DataGridViewCellMouseEventHandler(grid_RowHeaderMouseDoubleClick);
            grid.CellClick += new DataGridViewCellEventHandler(grid_CellClick);
            grid.KeyDown += new KeyEventHandler(grid_KeyDown);

            grid.AllowUserToOrderColumns = true;
            grid.SelectionMode = DataGridViewSelectionMode.CellSelect;
            //grid.ClipboardCopyMode = DataGridViewClipboardCopyMode.
            data.Controls.Add(grid);
            TabPage schema = new TabPage("Schema");
            schema.Name = "schemaTabPage";
            DataGridView schgrid = new DataGridView();
            schgrid.RowHeadersWidthSizeMode = DataGridViewRowHeadersWidthSizeMode.DisableResizing;
            schgrid.Dock = DockStyle.Fill;
            schema.Controls.Add(schgrid);
            dataAndSchema.TabPages.Add(data);
            dataAndSchema.TabPages.Add(schema);
            page.Controls.Add(dataAndSchema);
            resultsTabControl.TabPages.Add(page);
            dataAndSchema.SelectedTab = data;
            return page;
        }

        void grid_ColumnHeaderMouseDoubleClick(object sender, DataGridViewCellMouseEventArgs e)
        {
            //PagedGridView grid = sender as PagedGridView;
            //grid.VirtualMode = false;
            //grid.Sort(grid.Columns[e.ColumnIndex], ListSortDirection.Ascending);
        }

        void grid_RowHeaderMouseDoubleClick(object sender, DataGridViewCellMouseEventArgs e)
        {
        }

        void grid_KeyDown(object sender, KeyEventArgs e)
        {
            PagedGridView grid = sender as PagedGridView;
            if (e.Control && e.KeyCode == Keys.C)
            {
                int row = -1;
                foreach (DataGridViewCell cell in grid.SelectedCells)
                {
                    if (row == -1)
                        row = cell.RowIndex;
                    else if (row != cell.RowIndex)
                    {
                        grid.ClipboardCopyMode = DataGridViewClipboardCopyMode.EnableAlwaysIncludeHeaderText;
                        return;
                    }
                }
                grid.ClipboardCopyMode = DataGridViewClipboardCopyMode.EnableWithAutoHeaderText;
            }
        }

        void grid_CellClick(object sender, DataGridViewCellEventArgs e)
        {
            if (e.ColumnIndex == -1 || e.RowIndex == -1) return; // DataGridView calls CellClick before RowHeader and ColumnHeader click.
            PagedGridView grid = sender as PagedGridView;
            grid.SelectionMode = DataGridViewSelectionMode.CellSelect;
            grid.Rows[e.RowIndex].Cells[e.ColumnIndex].Selected = true;
        }

        void grid_RowHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
        {
            PagedGridView grid = sender as PagedGridView;
            if (grid.SelectionMode != DataGridViewSelectionMode.RowHeaderSelect)
            {
                grid.SelectionMode = DataGridViewSelectionMode.RowHeaderSelect;
                grid.Rows[e.RowIndex].Selected = true;
            }
        }

        void grid_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
        {
            PagedGridView grid = sender as PagedGridView;
            if (grid.SelectionMode != DataGridViewSelectionMode.ColumnHeaderSelect)
            {
                grid.SelectionMode = DataGridViewSelectionMode.ColumnHeaderSelect;
                grid.Columns[e.ColumnIndex].Selected = true;
            }
        }

        void grid_CellContextMenuStripNeeded(object sender, DataGridViewCellContextMenuStripNeededEventArgs e)
        {
            if (_tabMenus == null || e.RowIndex == -1) return;
            ContextMenuStrip menu = _tabMenus["EDITGRID"];
            if (menu != null)
            {
                DataGridView grid = sender as DataGridView;
                bool rowselected = grid.Rows[e.RowIndex].Selected;
                bool contextcellselected = e.ColumnIndex != -1 && grid.Rows[e.RowIndex].Cells[e.ColumnIndex].Selected;
                if (!rowselected && !contextcellselected)
                {
                    grid.ClearSelection();
                    grid.SelectionMode = DataGridViewSelectionMode.RowHeaderSelect;
                    grid.Rows[e.RowIndex].Selected = true;
                    rowselected = true;
                }
                if (rowselected)
                {
                    menu.Items["scriptCellsForUPDATEToolStripMenuItem"].Visible = false;
                }
                else
                {
                    menu.Items["scriptCellsForUPDATEToolStripMenuItem"].Visible = true;
                }
                e.ContextMenuStrip = menu;
            }
        }

        void grid_RowContextMenuStripNeeded(object sender, DataGridViewRowContextMenuStripNeededEventArgs e)
        {
            if (_tabMenus == null) return;
            ContextMenuStrip menu = _tabMenus["EDITGRID"];
            if (menu != null)
            {
                e.ContextMenuStrip = menu;
            }
        }

        void grid_DisableConstraints(object dataSource)
        {
            DataTable t = dataSource as DataTable;
            t.DataSet.EnforceConstraints = false;
        }

        public void DisableConstraints()
        {
            DataTable t = VisibleDataTable;
            if (t == null) return;
            grid_DisableConstraints(VisibleDataTable);
        }

        public void EnableConstraints()
        {
            DataTable t = VisibleDataTable;
            if (t == null) return;
            try
            {
                t.DataSet.EnforceConstraints = true;
            }
            catch (ConstraintException ex)
            {
                MessageBox.Show(ex.GetBaseException().Message);
            }
        }

        void grid_DoubleClick(object sender, EventArgs e)
        {
            //MessageBox.Show((sender as DataGridView).FirstDisplayedScrollingRowIndex.ToString());
        }

        public bool EnforceConstraints
        {
            get
            {
                DataTable t = VisibleDataTable;
                if (t == null) return true;
                return t.DataSet.EnforceConstraints;
            }
        }

        PagedGridView GetDataGrid(TabPage gridTab)
        {
            if (gridTab == null) return null;
            TabControl tc = gridTab.Controls[0] as TabControl;
            if (tc == null || tc.TabPages["dataTabPage"] == null) return null;
            return tc.TabPages["dataTabPage"].Controls[0] as PagedGridView;
        }

        DataGridView GetSchemaGrid(TabPage gridTab)
        {
            if (gridTab == null) return null;
            TabControl tc = gridTab.Controls[0] as TabControl;
            return tc.TabPages["schemaTabPage"].Controls[0] as DataGridView;
        }

        public DataTable VisibleDataTable
        {
            get
            {
                if (resultsTabControl.SelectedTab == null) return null;
                PagedGridView grid = GetDataGrid(resultsTabControl.SelectedTab);
                if (grid == null) return null;
                return grid.PagedDataSource as DataTable;
            }
        }

        TabPage CreateTextTab()
        {
            TabPage page = new TabPage("Messages");
            TextBox txt = new TextBox();
            txt.Text = @"";
            txt.Font = new Font("Tahoma", 8);
            txt.Multiline = true;
            txt.Dock = DockStyle.Fill;
            txt.DoubleClick += new EventHandler(txt_DoubleClick);
            txt.HideSelection = false;
            txt.ScrollBars = ScrollBars.Both;
            page.Controls.Add(txt);
            resultsTabControl.TabPages.Add(page);
            return page;
        }

        void txt_DoubleClick(object sender, EventArgs e)
        {
            TextBox txt = sender as TextBox;
            if (txt.SelectionStart < 0) return;

            int linestart = txt.GetFirstCharIndexOfCurrentLine();
            int icount = 0;
            int iline = 0;
            for (iline = 0; iline < txt.Lines.Length; iline++)
            {
                icount += txt.Lines[iline].Length + 2;
                if (icount > linestart) break;
            }

            //int iline = txt.GetLineFromCharIndex(txt.SelectionStart);
            //int linestart = txt.GetFirstCharIndexFromLine(iline);
            //int lineend = txt.GetFirstCharIndexFromLine(iline+1);
            //if (lineend == -1) lineend = txt.Text.Length - 1;
            //string line = txt.Text.Substring(linestart, lineend - linestart);
            if (iline >= txt.Lines.Length) return;
            string line = txt.Lines[iline];
            int pos1 = line.IndexOf("Line:");
            if (pos1 < 0) return;
            int pos2 = line.IndexOf(" ", pos1 + 5);
            if (pos2 < 0) return;
            string snum = line.Substring(pos1 + 5, pos2 - pos1 - 5);
            int num;
            if (int.TryParse(snum, out num))
            {
                if (num < 1) return;
                num -= 1;
                IDocument document = queryTextEditor.ActiveTextAreaControl.Document;
                if (num >= document.LineSegmentCollection.Count) return;
                LineSegment lineSegment = document.LineSegmentCollection[num];
                queryTextEditor.ActiveTextAreaControl.SelectionManager.ClearSelection();
                queryTextEditor.ActiveTextAreaControl.SelectionManager.SetSelection(new Point(0, num), new Point(lineSegment.Length, num));
                queryTextEditor.ActiveTextAreaControl.Caret.Line = num;
                queryTextEditor.ActiveTextAreaControl.ScrollTo(num);
                queryTextEditor.Focus();

                int linelength = line.Length;
                txt.SelectionStart = icount - linelength - 2;
                txt.SelectionLength = linelength;
                //int ci = txt.GetFirstCharIndexFromLine(iline);
                //txt.SelectionStart = ci + pos1;
                //txt.SelectionLength = pos2 - pos1;
            }
        }

        void AppendMessage(string text)
        {
            if (_textTab == null)
                _textTab = CreateTextTab();

            TextBox textBox = _textTab.Controls[0] as TextBox;
            textBox.AppendText(text);
            if (!text.EndsWith("\n"))
                textBox.AppendText("\r\n");
        }

        DataTable _loadingDataTable = null;
        TabPage _loadingResultTab = null;
        TabPage _textTab = null;

        void _execController_ExecuteAsyncMessage(string text)
        {
            AppendMessage(text);            
        }

        void _execController_ExecuteAsyncNewResult(StatementExecutionController.ExecuteNewResultEventArgs e)
        {
            _resultsCount++;
            TabPage tab = CreateGridTab();
            if (timerRowCount.Enabled == false)
                timerRowCount.Enabled = true;

            PagedGridView grid = GetDataGrid(tab);
            DataGridViewColumn col;
            foreach (DataRow schemarow in e.Schema.Rows)
            {
                col = new DataGridViewTextBoxColumn();
                col.DefaultCellStyle.NullValue = "NULL";
                col.Name = (string)schemarow["ColumnName"]+"column";
                col.HeaderText = (string)schemarow["ColumnName"];
                col.DataPropertyName = (string)schemarow["ColumnName"];
                col.ReadOnly = (bool)schemarow["IsReadOnly"];
                col.SortMode = DataGridViewColumnSortMode.Programmatic;
                grid.Columns.Add(col);
            }
            grid.PageNeeded += new PagedGridView.PageNeededDelegate(grid_PageNeeded);

            DataGridView schgrid = GetSchemaGrid(tab);
            schgrid.DataSource = e.Schema;

            grid.PagedDataSource = e.Data;
            _loadingDataTable = e.Data;
            _loadingResultTab = tab;
        }

        void _execController_ExecuteAsyncRowFetchComplete()
        {
            if (VisibleDataTable == _loadingDataTable)
                ReporRowCount(false);
            _loadingDataTable = null;
            PagedGridView grid = GetDataGrid(_loadingResultTab);
            if (grid != null)
            {
                grid.PageNeeded -= new PagedGridView.PageNeededDelegate(grid_PageNeeded);
                grid.NoMorePagesAvailable();
            }
        }

        void ReporRowCount(bool loading)
        {
            int rowcount = -1;
            lock (_execController.DataSet)
            {
                if (_loadingDataTable != null)
                    rowcount = _loadingDataTable.Rows.Count;
            }

            PagedGridView grid = GetDataGrid(_loadingResultTab);
            if (grid != null)
            {
                if (grid.RowCount == 0)
                    grid.RowCount = rowcount;

                if (StatusChange != null)
                    StatusChange.Invoke(rowcount, loading);
            }
        }

        private void timerRowCount_Tick(object sender, EventArgs e)
        {
            ReporRowCount(VisibleDataTable == _loadingDataTable);
        }

        void grid_PageNeeded(int rowIndex, int pageSize)
        {
            int rowcount = -1;
            lock (_execController.DataSet)
            {
                if (_loadingDataTable != null)
                    rowcount = _loadingDataTable.Rows.Count;
            }

            PagedGridView grid = GetDataGrid(_loadingResultTab);

            grid.RowCount = rowcount;

        }

        private bool ToggleLineComment(int currentLine, object bool_comment)
        {
            IDocument document = queryTextEditor.ActiveTextAreaControl.Document;
            LineSegment lineSegment = document.LineSegmentCollection[currentLine];// document.GetText(startOfLineOffset, length);
            string line = document.GetText(lineSegment.Offset, lineSegment.Length);

            string commentString = _connection.ConnectionProperties.LineCommentString;
            int commentpos = line.IndexOf(commentString);
            bool toComment;
            if (commentpos == -1)
                toComment = true;
            else
            {
                string beforeComment = line.Substring(0, commentpos);
                if (beforeComment.Trim() == "")
                    toComment = false;
                else
                    toComment = true;
            }
            if (toComment && (bool_comment == null || (bool)bool_comment == true))
            {
                document.Insert(lineSegment.Offset, commentString);
                return toComment;
            }
            else if (!toComment && (bool_comment == null || (bool)bool_comment == false))
            {
                document.Replace(lineSegment.Offset + commentpos, 2, "");
                return toComment;
            }
            return (bool)bool_comment;
        }

        public void ToggleLineComment()
        {
            IDocument document = queryTextEditor.ActiveTextAreaControl.Document;
            object lsc = document.LineSegmentCollection;
            SelectionManager sm = queryTextEditor.ActiveTextAreaControl.SelectionManager;
            int currentLine;
            object bool_comment = null;
            if (sm.HasSomethingSelected)
            {
                ISelection sel = sm.SelectionCollection[0];
                int delta = sel.EndPosition.Y-sel.StartPosition.Y;
                delta = delta / Math.Abs(delta);
                for (currentLine = sel.StartPosition.Y; currentLine != sel.EndPosition.Y + delta; currentLine += delta)
                {
                    bool_comment = ToggleLineComment(currentLine, bool_comment);
                }
            }
            else
            {
                currentLine = queryTextEditor.ActiveTextAreaControl.TextArea.Caret.Line;
                ToggleLineComment(currentLine, null);
            }
            //queryTextEditor.ActiveTextAreaControl.TextArea.Caret.Line
        }

        public void InsertDeclarationsRegion()
        {
            IDocument document = queryTextEditor.ActiveTextAreaControl.Document;
            Match match = TextUtils.MatchDeclareRegion(document.TextContent);
            if (match.Success)
            {
                queryTextEditor.ActiveTextAreaControl.ScrollTo(0);
                queryTextEditor.ActiveTextAreaControl.Caret.Position = new Point(0, document.OffsetToPosition(match.Index).Y);
            }
            else
            {
                document.Insert(0, "\r\n\r\n" + ConnectionInfo.ConnectionProperties.LineCommentString + " " + ENDREGION_DECLARE + "\r\n");
                queryTextEditor.Refresh();
            }
        }
        const string ENDREGION_DECLARE = "#endregion Declare";

        public void InsertLineAbove()
        {
            IDocument document = queryTextEditor.ActiveTextAreaControl.Document;
            document.Insert(document.LineSegmentCollection[queryTextEditor.ActiveTextAreaControl.Caret.Line].Offset ,"\r\n");
            queryTextEditor.Refresh();
        }


        public List<List<string>> GridSelectedCells
        {
            get
            {
                DataGridView grid = GetDataGrid(resultsTabControl.SelectedTab);
                List<int> rows = new List<int>();
                foreach (DataGridViewCell cell in grid.SelectedCells)
                {
                    int row = cell.RowIndex;
                    if (!rows.Contains(row))
                        rows.Add(row);
                }
                List<List<string>> rowsx = new List<List<string>>();
                foreach (int rowi in rows)
                {
                    List<string> vals = new List<string>();
                    DataGridViewRow row = grid.Rows[rowi];
                    foreach (DataGridViewCell cell in row.Cells)
                    {
                        if (cell.Selected)
                            vals.Add(grid.Columns[cell.ColumnIndex].DataPropertyName);
                    }
                    rowsx.Add(vals);
                }
                return rowsx;
            }
        }

        public List<Dictionary<string, object>> GridSelectionCurrentValues
        {
            get
            {
                DataGridView grid = GetDataGrid(resultsTabControl.SelectedTab);
                List<int> rows = new List<int>();
                foreach (DataGridViewCell cell in grid.SelectedCells)
                {
                    int row = cell.RowIndex;
                    if (!rows.Contains(row))
                        rows.Add(row);
                }
                rows.Sort();
                List<Dictionary<string, object>> rowsx = new List<Dictionary<string, object>>();
                foreach (int rowi in rows)
                {
                    Dictionary<string, object> vals = new Dictionary<string, object>();
                    DataGridViewRow row = grid.Rows[rowi];
                    foreach (DataGridViewCell cell in row.Cells)
                    {
                        vals.Add(grid.Columns[cell.ColumnIndex].DataPropertyName, cell.Value);
                    }
                    rowsx.Add(vals);
                }
                return rowsx;
            }
        }

        public List<Dictionary<string,object>> GridSelectionOriginalValues
        {
            get
            {
                DataGridView grid = GetDataGrid(resultsTabControl.SelectedTab);
                List<int> rows = new List<int>();
                foreach (DataGridViewCell cell in grid.SelectedCells)
                {
                    int row = cell.RowIndex;
                    if (!rows.Contains(row))
                        rows.Add(row);
                }
                rows.Sort();
                List<Dictionary<string, object>> rowsx = new List<Dictionary<string, object>>();
                foreach (int rowi in rows)
                {
                    Dictionary<string, object> vals = new Dictionary<string, object>();
                    DataGridViewRow row = grid.Rows[rowi];
                    foreach (DataGridViewCell cell in row.Cells)
                    {
                        vals.Add(grid.Columns[cell.ColumnIndex].DataPropertyName, cell.Value);
                    }
                    rowsx.Add(vals);
                }
                return rowsx;
            }
        }

        public void BuildEntityInfo(out List<DatabaseEntityInfo> tables, out List<DatabaseEntityInfo> columns)
        {
            DataTable schema = GetSchemaGrid(resultsTabControl.SelectedTab).DataSource as DataTable;
            List<string> tablenames = new List<string>();
            tables = new List<DatabaseEntityInfo>();
            columns = new List<DatabaseEntityInfo>();
            foreach (DataRow col in schema.Rows)
            {
                string tablename = null;
                if (col["BaseSchemaName"] != DBNull.Value && col["BaseTableName"] != DBNull.Value)
                    tablename = string.Format("[{0}].[{1}].[{2}].[{3}]", "�?", col["BaseCatalogName"], col["BaseSchemaName"], col["BaseTableName"]);

                if (!tablenames.Contains(tablename) && tablename != null)
                {
                    DatabaseEntityInfo table = new DatabaseEntityInfo();
                    table.DatabaseName = col["BaseCatalogName"] as string;
                    table.TableName = col["BaseTableName"] as string;
                    table.TableNamespace = col["BaseSchemaName"] as string;
                    table.TableType = "TABLE";
                    tables.Add(table);
                    tablenames.Add(tablename);
                }

                DatabaseEntityInfo column = new DatabaseEntityInfo();
                column.ColumnName = col["BaseColumnName"] as string;
                column.DatabaseName = col["BaseCatalogName"] as string;
                column.IsNullable = col["AllowDBNull"] != DBNull.Value ? (bool)col["AllowDBNull"] : false;
                column.IsPrimaryKey = col["IsKey"] != DBNull.Value ? (bool)col["IsKey"] : false;
                column.TableName = col["BaseTableName"] as string;
                column.TableNamespace = col["BaseSchemaName"] as string;
                column.TableType = "COLUMN";
                columns.Add(column);
            }
        }

        private void resultsTabControl_Selected(object sender, TabControlEventArgs e)
        {
            int rowcount = -1;
            DataTable t = VisibleDataTable;
            if (t != null)
                rowcount = t.Rows.Count;
            if (StatusChange != null)
                StatusChange.Invoke(rowcount, VisibleDataTable == _loadingDataTable);
        }

        internal void ToggleBookmark()
        {
            queryTextEditor.Document.BookmarkManager.ToggleMarkAt(queryTextEditor.ActiveTextAreaControl.Caret.Line);
            queryTextEditor.IsIconBarVisible = queryTextEditor.Document.BookmarkManager.Marks.Count > 0;
        }

        internal void GotoNextBookmark()
        {
            ICSharpCode.TextEditor.TextAreaControl textArea = queryTextEditor.ActiveTextAreaControl;
            Bookmark mark = queryTextEditor.Document.BookmarkManager.GetNextMark(queryTextEditor.ActiveTextAreaControl.Caret.Line);
            if (mark != null)
            {
                textArea.Caret.Line = mark.LineNumber;
                textArea.SelectionManager.ClearSelection();
            }
        }

        internal void GotoPreviousBookmark()
        {
            ICSharpCode.TextEditor.TextAreaControl textArea = queryTextEditor.ActiveTextAreaControl;
            Bookmark mark = queryTextEditor.Document.BookmarkManager.GetPrevMark(queryTextEditor.ActiveTextAreaControl.Caret.Line);
            if (mark != null)
            {
                textArea.Caret.Line = mark.LineNumber;
                textArea.SelectionManager.ClearSelection();
            }
        }

        internal List<KeyValuePair<string, ICSharpCode.TextEditor.Document.Bookmark>> ParseNamedBookmarks()
        {
            List<KeyValuePair<string, int>> list = _connection.ConnectionProperties.ParseNamedBookmarks(this.Script);
            if (list == null) return null;
            List<KeyValuePair<string, ICSharpCode.TextEditor.Document.Bookmark>> marks = new List<KeyValuePair<string, Bookmark>>();
            BookmarkManager marker = queryTextEditor.Document.BookmarkManager;
            foreach (KeyValuePair<string, int> item in list)
            {
                ICSharpCode.TextEditor.Document.Bookmark mark = new Bookmark(queryTextEditor.Document, item.Value);
                marker.AddMark(mark);
                marks.Add(new KeyValuePair<string, ICSharpCode.TextEditor.Document.Bookmark>(item.Key, mark));
            }
            queryTextEditor.IsIconBarVisible = queryTextEditor.Document.BookmarkManager.Marks.Count > 0;
            return marks;
        }

        internal void GotoBookmark(Bookmark mark)
        {
            ICSharpCode.TextEditor.TextAreaControl textArea = queryTextEditor.ActiveTextAreaControl;
            if (mark != null)
            {
                textArea.Caret.Line = mark.LineNumber;
                textArea.SelectionManager.ClearSelection();
                queryTextEditor.Focus();
            }
        }

        string _findFree = @"{0}";
        string _findWhole = @"\W{0}\W";
        bool eofind = false;
        internal void Find(string textToFind, FindOptions findOptions, bool forward)
        {
            string expr;
            if (findOptions.MatchWholeWord)
                expr = string.Format(_findWhole, textToFind);
            else
                expr = string.Format(_findFree, textToFind);

            RegexOptions options = RegexOptions.None;
            if (!forward)
                options |= RegexOptions.RightToLeft;

            Regex regex;
            if (findOptions.MatchCase)
                regex = new Regex(expr, options);
            else
                regex = new Regex(expr, options | RegexOptions.IgnoreCase);

            ICSharpCode.TextEditor.TextAreaControl textArea = queryTextEditor.ActiveTextAreaControl;
            Point[] prevsel = null;
            if (textArea.SelectionManager.HasSomethingSelected)
                prevsel = new Point[] { textArea.SelectionManager.SelectionCollection[0].StartPosition, textArea.SelectionManager.SelectionCollection[0].EndPosition };
            if (eofind)
            {
                int restartpos = 0;
                if (!forward)
                    restartpos = queryTextEditor.Text.Length - 1;
                Point start = textArea.Document.OffsetToPosition(restartpos);
                textArea.JumpTo(start.Y, start.X);
            }

            if (textArea.SelectionManager.HasSomethingSelected)
            {
                Point caret;
                if (forward)
                    caret = textArea.SelectionManager.SelectionCollection[0].EndPosition;
                else
                    caret = textArea.SelectionManager.SelectionCollection[0].StartPosition;

                textArea.JumpTo(caret.Y, caret.X);
            }

            Match match = regex.Match(queryTextEditor.Text, textArea.Caret.Offset);
            if (match.Success)
            {
                Point start = textArea.Document.OffsetToPosition(match.Index);
                textArea.JumpTo(start.Y, start.X);
                textArea.SelectionManager.SetSelection(start, textArea.Document.OffsetToPosition(match.Index + match.Length));
                eofind = false;
            }
            else
            {
                if (!eofind)
                {
                    eofind = true;
                    textArea.Enabled = false;
                    Application.DoEvents();
                    System.Threading.Thread.Sleep(500);
                    textArea.Enabled = true;
                }
                else
                {
                    eofind = false;
                    MessageBox.Show("Text not found");
                }
                if (prevsel != null)
                    textArea.SelectionManager.SetSelection(prevsel[0], prevsel[1]);
            }

        }

        internal void FindNext(string textToFind, FindOptions findOptions)
        {
            Find(textToFind, findOptions, true);
        }

        internal void FindPrevious(string textToFind, FindOptions findOptions)
        {
            Find(textToFind, findOptions, false);
        }

    }

    public class FindOptions
    {
        public FindOptions(bool matchCase, bool matchWholeWord)
        {
            this.MatchCase = matchCase;
            this.MatchWholeWord = matchWholeWord;
        }

        public bool MatchCase;
        public bool MatchWholeWord;
    }
}
































